package io.xxx.omni.sync.impl

import com.alibaba.fastjson.JSONObject
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
import io.xxx.omni.sync.*
import io.xxx.omni.util.toLocalDateTime
import org.apache.commons.codec.digest.DigestUtils
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpEntity
import org.springframework.http.HttpMethod
import org.springframework.stereotype.Component
import org.springframework.web.util.UriComponentsBuilder
import java.time.LocalDateTime
import java.util.*

/**
 * 爱库存
 */
abstract class AkcPorter : PagePorter() {

    @Autowired
    protected lateinit var akcActivityMapper: AkcActivityMapper

    private val httpUrl = "https://openapi.aikucun.com"

    override val platformCode = "aikucun"

    protected abstract val path: String

    protected fun getResponse(store: Store, params: Map<String, String> = emptyMap()): JSONObject {
        val signMap = TreeMap(params)
        val timestamp = System.currentTimeMillis()
        signMap["appid"] = store.appKey!!
        signMap["appsecret"] = store.appSecret!!
        signMap["noncestr"] = "1"
        signMap["erp"] = "Winner-ERP"
        signMap["erpversion"] = "1.0"
        signMap["timestamp"] = timestamp.toString()
        val builder = StringBuilder()
        signMap.onEachIndexed { index, (k, v) ->
            builder.append(k).append("=").append(v)
            if (index != signMap.size - 1) builder.append("&")
        }
        val sign = DigestUtils.sha1Hex(builder.toString())
        val urlBuilder = UriComponentsBuilder.fromHttpUrl(httpUrl)
        signMap.forEach { if (it.key != "appsecret") urlBuilder.queryParam(it.key, it.value) }
        val url = urlBuilder
            .path(path)
            .queryParam("sign", sign)
            .build(false).toUri()
        val response = restTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, JSONObject::class.java)
        if (response.statusCode.isError || response.body == null) {
            val msg = "接口[path: $path, queryParams: $signMap]异常"
            throw RuntimeException(msg)
        }
        val body = response.body!!
        if (body.getString("status") != "success") {
            val msg = "接口[path: $path, queryParams: $signMap]异常: $body"
            log.error(msg)
            throwException(path, body.getString("code"), body.getString("message"))
        }
        return response.body!!.getJSONObject("data")
    }

    companion object {
        private val log = LoggerFactory.getLogger(AkcPorter::class.java)
    }
}

@Component
class AkcActivityPorter : AkcPorter() {

    override val path = "/api/v2/activity/list"

    override val jobId = 3

    override fun pullAndSave(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        parameter: Any?
    ): List<String> {
        /*
        1 - 获取活动结束售后期的活动列表
        2 - 获取当前在线销售的活动列表
        9 - 同时获取在线销售的以及售后中的活动列表
         */
        val params = mapOf("status" to "9")
        val response = getResponse(store, params)
        val array = response.getJSONArray("list")
        array.forEach {
            @Suppress("unchecked_cast")
            val value = JSONObject(it as Map<String, Any>)
            val activity = AkcActivity(store, value)
            val oldActivity = akcActivityMapper.selectById(activity.id)
            if (oldActivity == null) {
                akcActivityMapper.insert(activity)
            } else if (oldActivity != activity) {
                akcActivityMapper.updateById(activity)
            }
        }
        return array.map { (it as Map<*, *>)["id"].toString() }
    }
}

@Component
class AkcTradePorter : AkcPorter() {

    override val path = "/api/v2/order/listall"

    override val jobId = 1

    override val cron = "0 */1 * * * ?"

    override val pageSize = 1000

    override fun getParameters(store: Store): List<Any> {
        val wrapper = QueryWrapper<AkcActivity>()
            .eq("store_code", store.code)
        return akcActivityMapper.selectList(wrapper)
    }

    override fun getCount(store: Store, startTime: LocalDateTime, endTime: LocalDateTime, parameter: Any?): Long? {
        if (parameter == null) {
            return 0
        }
        val params = getParams((parameter as AkcActivity).id!!)
        val response = getResponse(store, params)
        return response.getLong("totalrecord")
    }

    override fun getData(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        parameter: Any?,
        pageNo: Long,
    ): List<Document>? {
        val params = getParams((parameter as AkcActivity).id!!, pageNo)
        val response = getResponse(store, params)
        return response.getJSONArray("list")?.map {
            @Suppress("unchecked_cast")
            val value = JSONObject(it as Map<String, Any>)
            val modified = value.getString("paytime").toLocalDateTime()
                ?: value.getString("ordertime").toLocalDateTime()
            Document(value.getString("adorderid"), value, modified)
        }
    }

    private fun getParams(activityId: String, pageNo: Long = 1): Map<String, String> {
        return mapOf(
            "activityid" to activityId,
            "page" to pageNo.toString(),
            "pagesize" to pageSize.toString(),
        )
    }
}